package com.dianmi.seckill.common.log.impl;

import com.dianmi.seckill.common.log.LogEntity;
import com.dianmi.seckill.common.log.LogFactory;
import com.dianmi.seckill.common.log.LogTypeEnum;
import com.dianmi.seckill.common.utils.JsonUtil;
import org.apache.commons.lang.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author xieqiaofu
 * @date 2020/11/18
 */
public class DefaultLogFacotry implements LogFactory {

    public static final Class[] FILTER_CLAZZ = new Class[]{ServletRequest.class, ServletResponse.class};

    private Method method;

    private LogContext context;

    public DefaultLogFacotry(Method method, LogContext context) {
        this.method = method;
        this.context = context;
    }

    @Override
    public LogEntity create(Object[] args) {
        LogEntity log = new LogEntity();
        log.setLogType(LogTypeEnum.IN_METHOD);
        setCommonInfo(log);
        List<String> argString = excludeArgs(args);
        log.setSpan(StringUtils.join(argString, ","));
        return log;
    }

    @Override
    public LogEntity create(Object returnObj) {
        LogEntity log = new LogEntity();
        log.setLogType(LogTypeEnum.RETURN_METHOD);
        setCommonInfo(log);
        log.setSpan(JsonUtil.toJson(returnObj));
        return log;
    }

    @Override
    public LogEntity create(Throwable e) {
        LogEntity log = new LogEntity();
        log.setLogType(LogTypeEnum.THROWABLE);
        setCommonInfo(log);
        log.setSpan("内部错误");
        log.setThrowable(e);
        return log;
    }

    private void setCommonInfo(LogEntity log) {
        log.setClazz(method.getDeclaringClass());
        log.setMethodName(method.getName());
        log.setIndex(context.getEntityIndex());
    }

    private List<String> excludeArgs(Object[] args) {
        List<String> canLogArgs = new ArrayList<>();
        if (args == null) {
            return canLogArgs;
        }
        for (Object arg : args) {
            if (!needFilter(arg)) {
                canLogArgs.add(JsonUtil.toJson(arg));
            }
        }
        return canLogArgs;
    }

    private boolean needFilter(Object arg) {
        if (null == arg) {
            return true;
        }
        for (Class clazz : FILTER_CLAZZ) {
            if (clazz.isAssignableFrom(arg.getClass())) {
                return true;
            }
        }
        return false;
    }
}
